The data come from the Kaggle website and relate to the useage of weapons in the US in 2014-18 with reported fatalities, wounded people, gender and other interesting variables (approx. 240,000 observations). In addition, I downloaded data on the number of registered weapons, population in US cities, and population in particular states. An analysis will be carried out, preceded by cleaning and data preparation, followed by visualization. The description for variables in this dataset has been included in a separate file.
#Import necessary libraries
library(graphics)
library(lattice)
library(latticeExtra)
library(ggplot2)
library(gridExtra)
library(dplyr)
library(reshape)
library(lubridate)
library(knitr)
library(readr)
library(tibble)
library(stringr)
library(gridExtra)
library(scales)
library(lubridate)
library(ggrepel)
library(leaflet)
library(rgdal)
library(plotly)
library(splitstackshape)
library(grid)
library(car)
library(plotrix)
library(data.table)
library(readr)
#Load data into data frames
my_data_0 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files0.txt")
my_data_1 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files1.txt", header = FALSE)
my_data_2 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files2.txt", header = FALSE)
my_data_3 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files3.txt", header = FALSE)
my_data_4 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files4.txt", header = FALSE)
my_data_5 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files5.txt", header = FALSE)
my_data_6 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files6.txt", header = FALSE)
my_data_7 <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/split_files7.txt", header = FALSE)
guns_registered <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/Guns_registered2.txt")
USA_population <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/USA_population2.txt")
state_population <- read.delim("https://raw.githubusercontent.com/malewiczK/Data-Science-overall-projects/master/Data/state_usa.txt")
#Adding column names to data frames
colnames(my_data_1) <- colnames(my_data_0)
colnames(my_data_2) <- colnames(my_data_0)
colnames(my_data_3) <- colnames(my_data_0)
colnames(my_data_4) <- colnames(my_data_0)
colnames(my_data_5) <- colnames(my_data_0)
colnames(my_data_6) <- colnames(my_data_0)
colnames(my_data_7) <- colnames(my_data_0)
#Concatenating
gun_violence <- rbind(my_data_0,my_data_1,my_data_2,my_data_3,my_data_4,my_data_5,my_data_6,my_data_7)
#Chart 1
options(repr.plot.width = 7, repr.plot.height = 4)
gun5 <- filter(gun_violence, nr.of.guns.used < 6)
gun5.t <- count(gun5, "nr.of.guns.used")
ggplot(gun5, aes(x=nr.of.guns.used)) + geom_histogram(bins=9) + labs(x="Number of guns used in combat",
y = "Frequency", title= "Histogram of number of guns used")

The bar chart above shows the gender participation in incidents that took place in 2014-2018 in the USA. The vast majority of men. We do not know if these are only victims, or victims and attackers. We can therefore assume that there are more victims as well as male assailants.
#Chart 3/1
options(repr.plot.width = 6, repr.plot.height = 5)
colnames(guns_registered) <- c('ID', 'State', 'Nr_of_guns', 'Nr_of_guns_per_capita')
guns_registered_f1 <- filter(guns_registered, Nr_of_guns > 165)
guns_registered_f1$ID <- NULL
rejestr <- ggplot(guns_registered_f1, aes(x=reorder(State,-Nr_of_guns), y=Nr_of_guns))
rejestr + geom_bar(stat="identity", fill = "blue") + geom_text(aes(x=State, y=Nr_of_guns+20,label = Nr_of_guns))+
ggtitle("8 States with the highest rate of guns registered") +
labs(x="State",y="Number of guns registered") +
theme_classic()

The above bar chart presents eight US states with the largest number of registered weapons in thous. Most noticeably Texas, then California, Florida, Virginia etc. In the further part of the analysis I will try to see if it has an impact on the number of incidents / killings. It should also be remembered that these states belong to some of the largest population, hence the number of inhabitants may be different.
#Chart 3/2
options(repr.plot.width = 6, repr.plot.height = 5)
rejestr2 <- ggplot(guns_registered_f1, aes(x=reorder(State,-Nr_of_guns_per_capita), y=Nr_of_guns_per_capita))
rejestr2 + geom_bar(stat="identity", fill = "blue") + geom_text(aes(x=State, y=Nr_of_guns_per_capita+0.02
,label = Nr_of_guns_per_capita))+
ggtitle("8 States with the highest rate of guns registered") +
labs(x="State",y="Number of guns per capita") +
theme_classic() + scale_y_continuous(breaks=seq(0,0.5,by=0.1), limits=c(0,0.5))

When it comes to the number of weapons per capita, the most is in Virginia, followed by Arizona and Texas, which also had the largest amount of registered weapons in total.
#Chart 4
options(repr.plot.width = 5, repr.plot.height = 5)
gn <- tapply(gun_violence$n_injured, gun_violence$state, sum)
mm = melt(gn)
gun_violence_f1 <- filter(mm, value > 5000)
gun_violence_f1 <- gun_violence_f1 %>% arrange(desc(value))
gun_violence_f1$pct <- round(gun_violence_f1$value/sum(gun_violence_f1$value)*100, digits = 2)
gun_violence_f1$indices <- paste(gun_violence_f1$indices, gun_violence_f1$pct)
gun_violence_f1$indices <- paste(gun_violence_f1$indices,"%",sep="")
gun_violence_f1<-gun_violence_f1[order(gun_violence_f1[,2]),]
pie3D(x=gun_violence_f1[,2], labels = gun_violence_f1[,1], main="Number of injured",
col=rainbow(length(gun_violence_f1[,1])), theta=pi/3,explode=0.05,radius=1,labelcex=1)

The above pie chart shows the number of people injured in individual states. Interestingly, the states of New York and Illionois appeared, which did not appear in combination with registered weapons. Nevertheless, they are on the list of 6 states in which there was the highest number of wounded. 1/3 of injured people are in the state of Illionois.
#Chart 5
options(repr.plot.width = 7, repr.plot.height = 4)
bwplot(n_injured~date...year|gen, data=box, ylab = "Number of injured", xlab="",
main="Distribution of persons injured in specific years, divided by gender")

The above box chart shows the distribution of people injured during incidents in 2014-2018 divided into gender. With a slight advantage on the male side, it happened that more people were injured during the incident. Data from 2018 come from the first three months, that is from the first quarter. However, if this year ends without major massacres, it will mean a declining trend after 2017.
#Chart 6
kill <- gun_violence %>% select(n_killed, state,gender)
kill_m <- filter(kill, gender=="Male")
kill_f <- filter(kill, gender=="Femle")
kill1 <- aggregate(n_killed ~ state + gender, data = kill_m, sum)
kill2 <- aggregate(n_killed ~ state + gender, data = kill_f, sum)
guns_registered2 <- guns_registered
names(guns_registered2) <- c("id","state", "n_guns","n_guns_per_capita")
guns_registered2$id <- NULL
kill_m1 <- merge(kill1, guns_registered2, by="state")
kill_f1 <- merge(kill2, guns_registered2, by="state")
kill_mf <- rbind(kill_m1, kill_f1)
kill_mf$gen <- factor(kill_mf$gender, levels=c("Male","Femle"), labels = c("Male", "Female"))
kill_mf$gender <- NULL
options(scipen=999)
ggplot(kill_mf,aes(n_guns*1000,n_killed,size=n_guns_per_capita, colour=gen))+ geom_point()+
labs( x="Number of guns registered",y="Number of killed",title="Correlation between guns,victims and gender")+
scale_size(name="Number of guns per capita")+ scale_color_discrete(name="Gender")+
scale_x_continuous(labels=comma)

The above scatter plot shows the correlation between the number of registered weapons and the number of people killed. In addition, the size of the dot is expressed by the number of weapons per one inhabitant, and the color is separated by gender. The tendencies growing for both sexes, ie with the increase in the number of registered weapons, the number of people killed is increasing. Rather, we can say that the number of weapons per one inhabitant has no effect.
#Chart 7
library(plyr)
ggplotly(gun_violence %>% count("state") %>%
ggplot(aes(x=reorder(state, freq), y=freq, fill=freq, text=state)) +
geom_bar(stat='identity', fill='blue') + coord_flip() +
labs(x='', y='Number of incidents', title = "Number of incidents in specific states"),
tooltip=c("text", "y"), height = 750, width=800)
The above bar chart shows the number of people injured in individual states, this time illustrating the situation over the years 2014-2017. In Illinois, where the highest number of incidents occur and the highest number of injured people, in 2017 the number of incidents noticeably decreased. Similarly, the situation in other states, only California and Ohio, recorded a slight increase.
#Chart 9
options(repr.plot.width = 9, repr.plot.height = 6)
bn <- tapply(gun_violence$n_injured, gun_violence$city, sum)
mmm = melt(bn)
names(mmm) <- c("city","value")
c <- merge(mmm,USA_population, by="city")
c1 <- filter(c, value>1500)
names(c1) <- c("city", "value", "rank", "population", "density")
par(mai = c(1, 1, 1, 1), omi = c(0, 0, 0, 0))
barplot.xticks <- barplot(c1$population, col = "lightblue", axes=FALSE, xlim=c(0,7),ylim = c(0,2800000),
xlab = "Cities", ylab = "Population", xpd = FALSE)
box()
axis(1, at = barplot.xticks, labels = c("Baltimore","Chicago","Memphis","Milwaukee","New Orleans","Philadelphia"))
axis(2, at = seq(from = 0, to = 2800000, by = 200000), col = "lightblue", lwd = 2)
par(new = TRUE)
plot(barplot.xticks, c1$value, type = "b", lwd = 2, col = "red", pch = 16, cex = 1.5,
xlab = "", ann = FALSE, axes = FALSE, xlim=c(0,7), ylim = c(0, 11000),
yaxs = "i")
with(c1[,], text(c1$value, labels =c1[,2], pos = 3))
axis(4, col = "red", at = seq(from = 0, to = 12000, by = 2000) , lwd = 2)
mtext("Number of injured", side = 4, line = 3)
title("Population & Number of injured")

The above bar-linear diagram shows the dependence of the population of a given state, and the number of injured people. There is a correlation that the larger the population, the higher the number of people injured. In New Orleans, despite the population of 2/3 of Memphis population, the number of injured people was even higher by ~ 15%.
#Chart 10
options(repr.plot.width = 4, repr.plot.height = 4)
gn <- tapply(gun_violence$n_killed, gun_violence$date...year, sum)
nnn1 = melt(gn)
names(nnn1) <- c("Date", "Value")
nnn1$Date <- format(as.Date(nnn1$Date, format = "%Y-%m-%d"), "%Y")
nnn <- filter(nnn1, Date!=2018)
my_ts = ts(nnn, start = 2014, end = 2017, frequency = 1)
kol <- my_ts[,2]
xyplot(kol,panel = panel.xyarea, origin = 0,xlab="Year",
ylab="Number of killed",main="Number of killed in the USA year on year",
scales=list(x=list(at=seq(2014, 2017, 1)),y=list(at=seq(0, 16500, 600))))

The above chart illustrating the situation in 2014-2017 indicates that we have an increasing tendency of the number of people killed. Because the data from 2018 come from the first quarter, speculations regarding the continuing upward trend will be carried out later.
#Chart 12
options(repr.plot.width = 7, repr.plot.height = 6)
gun_violence$dateChar <- as.Date(gun_violence$date)
gun_violence$dateChar <- ymd(gun_violence$dateChar)
str(gun_violence$dateChar)
Date[1:239399], format: "2014-05-26" "2014-05-22" "2014-05-23" "2014-05-26" "2014-06-02" "2014-06-02" "2014-05-28" "2014-05-30" "2014-05-29" "2014-04-26" ...
gun_violence$qu <- quarter(gun_violence$dateChar)
gun_violence$yr <- year(gun_violence$dateChar)
gun_violence2 <- gun_violence[,27:28]
q1 <- count(gun_violence2, c("qu", "yr"))%>%
ggplot(aes(x=as.factor(qu), y=freq)) + geom_bar(stat='identity', fill='blue') +
scale_y_continuous(labels=comma) + facet_grid(.~yr) + labs(x='Quarter', y='Number of incidents')
q2 <- count(gun_violence2, c("qu", "yr"))%>% filter(qu==1) %>%
ggplot(aes(x=as.factor(yr), y=freq)) + geom_bar(stat='identity', fill='blue') +
scale_y_continuous(labels=comma) + labs(x='Incidents in Q1 of each year', y='Number of incidents')
grid.arrange(q1, q2)

The above graphs will approximate the answer regarding the upward trend in the number of incidents. There seems to be some “seasonality” in Q1 and Q4, which generally have a smaller number of incidents than in Q2 and Q3. The second chart shows that in Q1 2018 there were fewer incidents than in Q1 2017. It can be considered a quite positive signal. However, it should be remembered that this number is still very high compared to other countries (relatively).
Quarterly analysis shows that more incidents occur in warmer spring and summer seasons. It seems that it is worth taking a closer look at this. In order to compare months, I exclude 2018 because it is not complete.
#Chart 13
gun_violence$mo <- lubridate::month(gun_violence$dateChar, label=TRUE)
ggplotly(gun_violence %>% filter(yr!=c(2013, 2018)) %>% count("mo") %>%
ggplot(aes(x=mo, y=freq)) + geom_bar(stat='identity', fill='blue') +
scale_y_continuous(labels=comma) +
labs(x='Month', y='Number of incidents', title='Incidents by Month'))
longer object length is not a multiple of shorter object length
The most visible “seasonality” is the observation that fewer incidents happen in cooler months. November, December and February is 3 months with the lowest number of incidents (February, of course, only 28 days). The only exception is January, which is worth investigating later. Probably incidents during the New Year period contribute to the fact that January has a large number of incidents.
The second peak is the period July / August. Probably because many people go on vacation during this period.
#Chart 14
options(repr.plot.width = 6, repr.plot.height = 4)
gun_violence$da <- day(gun_violence$dateChar)
gun_violence <- gun_violence %>% mutate(dateChar2=paste(mo, da))
jan <- gun_violence %>% filter(yr!=c("2013", "2018")) %>% count("dateChar2") %>% top_n(10) %>% arrange(desc(freq))
longer object length is not a multiple of shorter object lengthSelecting by freq
ggplot(jan,aes(x=reorder(dateChar2,-freq),y=freq)) + geom_bar(stat="identity",position="dodge", fill="blue") +
labs(x="The most common days",y="Number of incidents", title="The most dangerous days")

The above graph shows that enriched data, which are related to the population of each state, present a very different picture. As the number of incidents is related to the size of the population, these numbers now represent the “real” threat level of the operation of the weapon. To show it visually, I used color codes. Red indicates a high level of danger in terms of the relative number of incidents, and yellow indicates that the state is relatively safe.
Alaska, Louisiana and Delaware now show the highest relative numbers of incidents. Hawaii seems to be the safest country to live in, and the large state of California falls from the second state in terms of absolute incidents to a low position, adjusted for a large population.
#Chart 16 Number of incidents per 100,000 inhabitants in specific states
library(httr)
setwd(".")
url <- "https://github.com/malewiczK/Data-Science-overall-projects/blob/master/MapsData/Maps.zip?raw=true"
download.file(url, dest="Maps.zip", mode="wb")
trying URL 'https://github.com/malewiczK/Data-Science-overall-projects/blob/master/MapsData/Maps.zip?raw=true'
Content type 'application/zip' length 3334807 bytes (3.2 MB)
downloaded 3.2 MB
unzip("Maps.zip",exdir="./Maps")
dir("./Maps")
[1] "cb_2017_us_state_500k.cpg" "cb_2017_us_state_500k.dbf" "cb_2017_us_state_500k.prj"
[4] "cb_2017_us_state_500k.shp" "cb_2017_us_state_500k.shp.ea.iso.xml" "cb_2017_us_state_500k.shp.iso.xml"
[7] "cb_2017_us_state_500k.shp.xml" "cb_2017_us_state_500k.shx"
library(rgdal)
states <- readOGR(dsn = "./Maps",
layer = "cb_2017_us_state_500k",
encoding = "UTF-8")
OGR data source with driver: ESRI Shapefile
Source: "C:\Users\Karol\Desktop\markdown\R-analysis\Maps", layer: "cb_2017_us_state_500k"
with 56 features
It has 9 fields
Integer64 fields read as strings: ALAND AWATER
addPer100k <- data.frame(id=states$GEOID, name=states$NAME)
names(addPer100k) <- c("id", "state")
addPer100k <- left_join(addPer100k, incidentsByState %>% select(state, Per100000), by="state")
Column `state` joining factor and character vector, coercing into character vector
addPer100k$Per100000[is.na(addPer100k$Per100000)] <- 0
states$per100k <- addPer100k$Per100000
bins <- c(0, 50, 75, 100, 150, Inf)
pal <- colorBin("Blues", domain = states$per100k, bins = bins)
state_popup <- paste0("<strong>State: </strong>",
states$NAME,
"<br><strong>Incidents per 100,000 inhabitants </strong>",
states$per100k) %>% lapply(htmltools::HTML)
leaflet(data = states) %>%
setView(lng=-96, lat=37.8, zoom=3) %>%
addProviderTiles("MapBox", options = providerTileOptions(id = "mapbox.light",
accessToken = Sys.getenv('MAPBOX_ACCESS_TOKEN'))) %>%
addPolygons(
fillColor = ~pal(per100k),
weight = 2,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = state_popup,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(pal = pal, values = ~per100k, opacity = 0.7, title = "Incidents", position = "bottomleft")
The above map presents data on the number of incidents per 100,000 inhabitants. The above data has already been described in the previous part of the analysis.
#Chart 17 Incidents with highest numbers of victims
Top10 <- gun_violence %>% select(dateChar, n_killed, n_injured, n_victims,
location_description, city, state, latitude, longitude)
names(Top10) <- c("Date", "Killed", "Injured", "Victims", "Location", "City", "State",
"latitude","longitude")
toop10 <- Top10 %>% arrange(desc(Victims)) %>% top_n(n=13, wt=Victims)
TopMap <- toop10 %>% select(latitude, longitude, Victims, City, Location)
labels <- paste0("<strong>City: </strong>", TopMap$City,
"<br><strong>Location: </strong>", TopMap$Location,
"<br><strong>Victims </strong>", TopMap$Victims) %>% lapply(htmltools::HTML)
leaflet(TopMap) %>%
setView(lng=-96, lat=37.8, zoom=4) %>%
addTiles() %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(~longitude, ~latitude, color = "blue", radius=~sqrt(Victims), label = labels)
The above map presents data on places where incidents with the largest number of injured persons occurred. Visible a large number of points in Texas, California and Florida.
#Chart 18
gun_violence$incident_characteristics <- gsub("\\|\\|", "|", gun_violence$incident_characteristics)
IncCharac <- cSplit(gun_violence %>%
select(state, city, incident_characteristics),
'incident_characteristics', sep = '|', direction="long")
options(repr.plot.width = 20, repr.plot.height = 7)
IncCharac %>% count("incident_characteristics") %>% top_n(30, wt=freq) %>%
ggplot(aes(x=reorder(incident_characteristics, freq), y=freq),height = 750, width=1500) +
geom_bar(stat='identity', fill='red') +
coord_flip() + labs(x='Incident Category', y="",title="Number of incidents")

The above chart shows the places where incidents most often occurred. It turns out that the most common incidents occur in known, liked and frequented places such as shops, fast-food, and gas stations.
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGtlZXBfbWQ6IHRydWUNCiAgZ2l0aHViX2RvY3VtZW50Og0KICAgIG1kX2V4dGVuc2lvbnM6IC1hdXRvbGlua19iYXJlX3VyaXMraGFyZF9saW5lX2JyZWFrcw0KLS0tDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBmaWcucGF0aCA9ICJSRUFETUVfZmlncy9SRUFETUUtIg0KKQ0KYGBgDQoNCi0tLQ0KdGl0bGU6ICcjIEd1biBWaW9sZW5jZSAtIFVTQSAyMDE0LTIwMTggJw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KLS0tDQojIyMgVGhlIGRhdGEgY29tZSBmcm9tIHRoZSBLYWdnbGUgd2Vic2l0ZSBhbmQgcmVsYXRlIHRvIHRoZSB1c2VhZ2Ugb2Ygd2VhcG9ucyBpbiB0aGUgVVMgaW4gMjAxNC0xOCB3aXRoIHJlcG9ydGVkIGZhdGFsaXRpZXMsIHdvdW5kZWQgcGVvcGxlLCBnZW5kZXIgYW5kIG90aGVyIGludGVyZXN0aW5nIHZhcmlhYmxlcyAoYXBwcm94LiAyNDAsMDAwIG9ic2VydmF0aW9ucykuIEluIGFkZGl0aW9uLCBJIGRvd25sb2FkZWQgZGF0YSBvbiB0aGUgbnVtYmVyIG9mIHJlZ2lzdGVyZWQgd2VhcG9ucywgcG9wdWxhdGlvbiBpbiBVUyBjaXRpZXMsIGFuZCBwb3B1bGF0aW9uIGluIHBhcnRpY3VsYXIgc3RhdGVzLiBBbiBhbmFseXNpcyB3aWxsIGJlIGNhcnJpZWQgb3V0LCBwcmVjZWRlZCBieSBjbGVhbmluZyBhbmQgZGF0YSBwcmVwYXJhdGlvbiwgZm9sbG93ZWQgYnkgdmlzdWFsaXphdGlvbi4gVGhlIGRlc2NyaXB0aW9uIGZvciB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhc2V0IGhhcyBiZWVuIGluY2x1ZGVkIGluIGEgc2VwYXJhdGUgZmlsZS4NCg0KYGBge3J9DQojSW1wb3J0IG5lY2Vzc2FyeSBsaWJyYXJpZXMNCg0KbGlicmFyeShncmFwaGljcykNCmxpYnJhcnkobGF0dGljZSkNCmxpYnJhcnkobGF0dGljZUV4dHJhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShyZXNoYXBlKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkodGliYmxlKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShzcGxpdHN0YWNrc2hhcGUpDQpsaWJyYXJ5KGdyaWQpDQpsaWJyYXJ5KGNhcikNCmxpYnJhcnkocGxvdHJpeCkNCmxpYnJhcnkoZGF0YS50YWJsZSkNCmxpYnJhcnkocmVhZHIpDQoNCmBgYA0KDQpgYGB7cn0NCiNMb2FkIGRhdGEgaW50byBkYXRhIGZyYW1lcw0KDQpteV9kYXRhXzAgPC0gcmVhZC5kZWxpbSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL21hbGV3aWN6Sy9EYXRhLVNjaWVuY2Utb3ZlcmFsbC1wcm9qZWN0cy9tYXN0ZXIvRGF0YS9zcGxpdF9maWxlczAudHh0IikNCm15X2RhdGFfMSA8LSByZWFkLmRlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWFsZXdpY3pLL0RhdGEtU2NpZW5jZS1vdmVyYWxsLXByb2plY3RzL21hc3Rlci9EYXRhL3NwbGl0X2ZpbGVzMS50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCm15X2RhdGFfMiA8LSByZWFkLmRlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWFsZXdpY3pLL0RhdGEtU2NpZW5jZS1vdmVyYWxsLXByb2plY3RzL21hc3Rlci9EYXRhL3NwbGl0X2ZpbGVzMi50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCm15X2RhdGFfMyA8LSByZWFkLmRlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWFsZXdpY3pLL0RhdGEtU2NpZW5jZS1vdmVyYWxsLXByb2plY3RzL21hc3Rlci9EYXRhL3NwbGl0X2ZpbGVzMy50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCm15X2RhdGFfNCA8LSByZWFkLmRlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWFsZXdpY3pLL0RhdGEtU2NpZW5jZS1vdmVyYWxsLXByb2plY3RzL21hc3Rlci9EYXRhL3NwbGl0X2ZpbGVzNC50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCm15X2RhdGFfNSA8LSByZWFkLmRlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWFsZXdpY3pLL0RhdGEtU2NpZW5jZS1vdmVyYWxsLXByb2plY3RzL21hc3Rlci9EYXRhL3NwbGl0X2ZpbGVzNS50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCm15X2RhdGFfNiA8LSByZWFkLmRlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWFsZXdpY3pLL0RhdGEtU2NpZW5jZS1vdmVyYWxsLXByb2plY3RzL21hc3Rlci9EYXRhL3NwbGl0X2ZpbGVzNi50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCm15X2RhdGFfNyA8LSByZWFkLmRlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWFsZXdpY3pLL0RhdGEtU2NpZW5jZS1vdmVyYWxsLXByb2plY3RzL21hc3Rlci9EYXRhL3NwbGl0X2ZpbGVzNy50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCg0KZ3Vuc19yZWdpc3RlcmVkIDwtIHJlYWQuZGVsaW0oImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9tYWxld2ljeksvRGF0YS1TY2llbmNlLW92ZXJhbGwtcHJvamVjdHMvbWFzdGVyL0RhdGEvR3Vuc19yZWdpc3RlcmVkMi50eHQiKQ0KVVNBX3BvcHVsYXRpb24gPC0gcmVhZC5kZWxpbSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL21hbGV3aWN6Sy9EYXRhLVNjaWVuY2Utb3ZlcmFsbC1wcm9qZWN0cy9tYXN0ZXIvRGF0YS9VU0FfcG9wdWxhdGlvbjIudHh0IikNCnN0YXRlX3BvcHVsYXRpb24gPC0gcmVhZC5kZWxpbSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL21hbGV3aWN6Sy9EYXRhLVNjaWVuY2Utb3ZlcmFsbC1wcm9qZWN0cy9tYXN0ZXIvRGF0YS9zdGF0ZV91c2EudHh0IikNCmBgYA0KDQpgYGB7cn0NCiNBZGRpbmcgY29sdW1uIG5hbWVzIHRvIGRhdGEgZnJhbWVzDQoNCmNvbG5hbWVzKG15X2RhdGFfMSkgPC0gY29sbmFtZXMobXlfZGF0YV8wKQ0KY29sbmFtZXMobXlfZGF0YV8yKSA8LSBjb2xuYW1lcyhteV9kYXRhXzApDQpjb2xuYW1lcyhteV9kYXRhXzMpIDwtIGNvbG5hbWVzKG15X2RhdGFfMCkNCmNvbG5hbWVzKG15X2RhdGFfNCkgPC0gY29sbmFtZXMobXlfZGF0YV8wKQ0KY29sbmFtZXMobXlfZGF0YV81KSA8LSBjb2xuYW1lcyhteV9kYXRhXzApDQpjb2xuYW1lcyhteV9kYXRhXzYpIDwtIGNvbG5hbWVzKG15X2RhdGFfMCkNCmNvbG5hbWVzKG15X2RhdGFfNykgPC0gY29sbmFtZXMobXlfZGF0YV8wKQ0KYGBgDQoNCmBgYHtyfQ0KI0NvbmNhdGVuYXRpbmcNCg0KZ3VuX3Zpb2xlbmNlIDwtIHJiaW5kKG15X2RhdGFfMCxteV9kYXRhXzEsbXlfZGF0YV8yLG15X2RhdGFfMyxteV9kYXRhXzQsbXlfZGF0YV81LG15X2RhdGFfNixteV9kYXRhXzcpDQoNCiNDaGFydCAxDQoNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gNywgcmVwci5wbG90LmhlaWdodCA9IDQpDQpndW41IDwtIGZpbHRlcihndW5fdmlvbGVuY2UsIG5yLm9mLmd1bnMudXNlZCA8IDYpDQpndW41LnQgPC0gY291bnQoZ3VuNSwgIm5yLm9mLmd1bnMudXNlZCIpDQpnZ3Bsb3QoZ3VuNSwgYWVzKHg9bnIub2YuZ3Vucy51c2VkKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zPTkpICsgbGFicyh4PSJOdW1iZXIgb2YgZ3VucyB1c2VkIGluIGNvbWJhdCIsDQogICAgIHkgPSAiRnJlcXVlbmN5IiwgdGl0bGU9ICJIaXN0b2dyYW0gb2YgbnVtYmVyIG9mIGd1bnMgdXNlZCIpDQpgYGANCg0KIyMjIFRoZSBhYm92ZSBoaXN0b2dyYW0gIHNob3dzIHRoZSBudW1iZXIgb2Ygd2VhcG9ucyB1c2VkIGR1cmluZyB0aGUgaW5jaWRlbnQsIHdoaWNoIHdhcyBtb3N0IGZyZXF1ZW50bHkgcmVjb3JkZWQgaW4gdGhlIHllYXJzIDIwMTQtMjAxOC4gVGhlcmUgaXMgZGVmaW5pdGVseSAxIHBjcyBvZiB3ZWFwb24sIHdoaWNoIGlzIHVzZWQgZHVyaW5nIHRoZSBhc3NhdWx0LiBUaGUgaGlzdG9ncmFtIG9taXRzIG9ic2VydmF0aW9ucyB0aGF0IGRpZCBub3QgaGF2ZSBhbiBhc3NpZ25lZCBudW1iZXIgb2Ygd2VhcG9ucyB1c2VkIGR1cmluZyB0aGUgaW5jaWRlbnQgKG1vcmUgb3IgbGVzcyBoYWxmIG9mIHRoZSBvYnNlcnZhdGlvbnMgZGlkIG5vdCBoYXZlIHN1Y2ggaW5mb3JtYXRpb24pLg0KDQpgYGB7cn0NCiNDaGFydCAyDQoNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMywgcmVwci5wbG90LmhlaWdodCA9IDQpDQpib3ggPC0gZ3VuX3Zpb2xlbmNlICU+JSBzZWxlY3QoZGF0ZS4uLnllYXIsIG5faW5qdXJlZCwgZ2VuZGVyKQ0KYm94JGRhdGUuLi55ZWFyIDwtIGZvcm1hdChhcy5EYXRlKGJveCRkYXRlLi4ueWVhciwgZm9ybWF0ID0gIiVZLSVtLSVkIiksICIlWSIpDQpib3ggPC0gZmlsdGVyKGJveCxnZW5kZXIhPSIiKSANCmJveCRnZW4gPC0gZmFjdG9yKGJveCRnZW5kZXIsIGxldmVscz1jKCJNYWxlIiwiRmVtbGUiKSwgbGFiZWxzID0gYygiTWFsZSIsICJGZW1hbGUiKSkNCmJveCRnZW5kZXIgPC0gTlVMTA0KYmFycGxvdCh0YWJsZShmYWN0b3IoYm94JGdlbikpLCBtYWluPSJDb21wYXJpc29uIG9mIGdlbmRlciIsIA0KICAgICAgICB5bGFiPSJGcmVxdWVuY3kiLCBheGVzPUZBTFNFLCB5bGltID0gYygwLDIwMDAwMCkpDQpheGlzKDIsIGF0ID0gc2VxKGZyb20gPSAwLCB0byA9IDIwMDAwMCwgYnkgPSAyMDAwMCkpDQpgYGANCg0KIyMjIFRoZSBiYXIgY2hhcnQgYWJvdmUgc2hvd3MgdGhlIGdlbmRlciBwYXJ0aWNpcGF0aW9uIGluIGluY2lkZW50cyB0aGF0IHRvb2sgcGxhY2UgaW4gMjAxNC0yMDE4IGluIHRoZSBVU0EuIFRoZSB2YXN0IG1ham9yaXR5IG9mIG1lbi4gV2UgZG8gbm90IGtub3cgaWYgdGhlc2UgYXJlIG9ubHkgdmljdGltcywgb3IgdmljdGltcyBhbmQgYXR0YWNrZXJzLiBXZSBjYW4gdGhlcmVmb3JlIGFzc3VtZSB0aGF0IHRoZXJlIGFyZSBtb3JlIHZpY3RpbXMgYXMgd2VsbCBhcyBtYWxlIGFzc2FpbGFudHMuDQoNCmBgYHtyfQ0KI0NoYXJ0IDMvMQ0KDQpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDYsIHJlcHIucGxvdC5oZWlnaHQgPSA1KQ0KY29sbmFtZXMoZ3Vuc19yZWdpc3RlcmVkKSA8LSBjKCdJRCcsICdTdGF0ZScsICdOcl9vZl9ndW5zJywgJ05yX29mX2d1bnNfcGVyX2NhcGl0YScpDQpndW5zX3JlZ2lzdGVyZWRfZjEgPC0gZmlsdGVyKGd1bnNfcmVnaXN0ZXJlZCwgTnJfb2ZfZ3VucyA+IDE2NSkNCmd1bnNfcmVnaXN0ZXJlZF9mMSRJRCA8LSBOVUxMDQpyZWplc3RyIDwtIGdncGxvdChndW5zX3JlZ2lzdGVyZWRfZjEsIGFlcyh4PXJlb3JkZXIoU3RhdGUsLU5yX29mX2d1bnMpLCB5PU5yX29mX2d1bnMpKQ0KDQpyZWplc3RyICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsID0gImJsdWUiKSArIGdlb21fdGV4dChhZXMoeD1TdGF0ZSwgeT1Ocl9vZl9ndW5zKzIwLGxhYmVsID0gTnJfb2ZfZ3VucykpKw0KICBnZ3RpdGxlKCI4IFN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IHJhdGUgb2YgZ3VucyByZWdpc3RlcmVkIikgKyANCiAgbGFicyh4PSJTdGF0ZSIseT0iTnVtYmVyIG9mIGd1bnMgcmVnaXN0ZXJlZCIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KIyMjIFRoZSBhYm92ZSBiYXIgY2hhcnQgcHJlc2VudHMgZWlnaHQgVVMgc3RhdGVzIHdpdGggdGhlIGxhcmdlc3QgbnVtYmVyIG9mIHJlZ2lzdGVyZWQgd2VhcG9ucyBpbiB0aG91cy4gTW9zdCBub3RpY2VhYmx5IFRleGFzLCB0aGVuIENhbGlmb3JuaWEsIEZsb3JpZGEsIFZpcmdpbmlhIGV0Yy4gSW4gdGhlIGZ1cnRoZXIgcGFydCBvZiB0aGUgYW5hbHlzaXMgSSB3aWxsIHRyeSB0byBzZWUgaWYgaXQgaGFzIGFuIGltcGFjdCBvbiB0aGUgbnVtYmVyIG9mIGluY2lkZW50cyAvIGtpbGxpbmdzLiBJdCBzaG91bGQgYWxzbyBiZSByZW1lbWJlcmVkIHRoYXQgdGhlc2Ugc3RhdGVzIGJlbG9uZyB0byBzb21lIG9mIHRoZSBsYXJnZXN0IHBvcHVsYXRpb24sIGhlbmNlIHRoZSBudW1iZXIgb2YgaW5oYWJpdGFudHMgbWF5IGJlIGRpZmZlcmVudC4NCg0KYGBge3J9DQojQ2hhcnQgMy8yDQoNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gNiwgcmVwci5wbG90LmhlaWdodCA9IDUpDQpyZWplc3RyMiA8LSBnZ3Bsb3QoZ3Vuc19yZWdpc3RlcmVkX2YxLCBhZXMoeD1yZW9yZGVyKFN0YXRlLC1Ocl9vZl9ndW5zX3Blcl9jYXBpdGEpLCB5PU5yX29mX2d1bnNfcGVyX2NhcGl0YSkpDQoNCnJlamVzdHIyICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsID0gImJsdWUiKSArIGdlb21fdGV4dChhZXMoeD1TdGF0ZSwgeT1Ocl9vZl9ndW5zX3Blcl9jYXBpdGErMC4wMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxsYWJlbCA9IE5yX29mX2d1bnNfcGVyX2NhcGl0YSkpKw0KICBnZ3RpdGxlKCI4IFN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IHJhdGUgb2YgZ3VucyByZWdpc3RlcmVkIikgKw0KICBsYWJzKHg9IlN0YXRlIix5PSJOdW1iZXIgb2YgZ3VucyBwZXIgY2FwaXRhIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDAuNSxieT0wLjEpLCBsaW1pdHM9YygwLDAuNSkpDQpgYGANCg0KIyMjIFdoZW4gaXQgY29tZXMgdG8gdGhlIG51bWJlciBvZiB3ZWFwb25zIHBlciBjYXBpdGEsIHRoZSBtb3N0IGlzIGluIFZpcmdpbmlhLCBmb2xsb3dlZCBieSBBcml6b25hIGFuZCBUZXhhcywgd2hpY2ggYWxzbyBoYWQgdGhlIGxhcmdlc3QgYW1vdW50IG9mIHJlZ2lzdGVyZWQgd2VhcG9ucyBpbiB0b3RhbC4NCg0KYGBge3J9DQojQ2hhcnQgNA0KDQpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDUsIHJlcHIucGxvdC5oZWlnaHQgPSA1KQ0KZ24gPC0gdGFwcGx5KGd1bl92aW9sZW5jZSRuX2luanVyZWQsIGd1bl92aW9sZW5jZSRzdGF0ZSwgc3VtKQ0KbW0gPSBtZWx0KGduKQ0KDQpndW5fdmlvbGVuY2VfZjEgPC0gZmlsdGVyKG1tLCB2YWx1ZSA+IDUwMDApIA0KZ3VuX3Zpb2xlbmNlX2YxIDwtIGd1bl92aW9sZW5jZV9mMSAlPiUgYXJyYW5nZShkZXNjKHZhbHVlKSkNCg0KZ3VuX3Zpb2xlbmNlX2YxJHBjdCA8LSByb3VuZChndW5fdmlvbGVuY2VfZjEkdmFsdWUvc3VtKGd1bl92aW9sZW5jZV9mMSR2YWx1ZSkqMTAwLCBkaWdpdHMgPSAyKQ0KZ3VuX3Zpb2xlbmNlX2YxJGluZGljZXMgPC0gcGFzdGUoZ3VuX3Zpb2xlbmNlX2YxJGluZGljZXMsIGd1bl92aW9sZW5jZV9mMSRwY3QpDQpndW5fdmlvbGVuY2VfZjEkaW5kaWNlcyA8LSBwYXN0ZShndW5fdmlvbGVuY2VfZjEkaW5kaWNlcywiJSIsc2VwPSIiKQ0KZ3VuX3Zpb2xlbmNlX2YxPC1ndW5fdmlvbGVuY2VfZjFbb3JkZXIoZ3VuX3Zpb2xlbmNlX2YxWywyXSksXQ0KDQpwaWUzRCh4PWd1bl92aW9sZW5jZV9mMVssMl0sIGxhYmVscyA9IGd1bl92aW9sZW5jZV9mMVssMV0sIG1haW49Ik51bWJlciBvZiBpbmp1cmVkIiwNCiAgICAgIGNvbD1yYWluYm93KGxlbmd0aChndW5fdmlvbGVuY2VfZjFbLDFdKSksIHRoZXRhPXBpLzMsZXhwbG9kZT0wLjA1LHJhZGl1cz0xLGxhYmVsY2V4PTEpDQpgYGANCg0KIyMjIFRoZSBhYm92ZSBwaWUgY2hhcnQgc2hvd3MgdGhlIG51bWJlciBvZiBwZW9wbGUgaW5qdXJlZCBpbiBpbmRpdmlkdWFsIHN0YXRlcy4gSW50ZXJlc3RpbmdseSwgdGhlIHN0YXRlcyBvZiBOZXcgWW9yayBhbmQgSWxsaW9ub2lzIGFwcGVhcmVkLCB3aGljaCBkaWQgbm90IGFwcGVhciBpbiBjb21iaW5hdGlvbiB3aXRoIHJlZ2lzdGVyZWQgd2VhcG9ucy4gTmV2ZXJ0aGVsZXNzLCB0aGV5IGFyZSBvbiB0aGUgbGlzdCBvZiA2IHN0YXRlcyBpbiB3aGljaCB0aGVyZSB3YXMgdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHdvdW5kZWQuIDEvMyBvZiBpbmp1cmVkIHBlb3BsZSBhcmUgaW4gdGhlIHN0YXRlIG9mIElsbGlvbm9pcy4NCg0KYGBge3J9DQojQ2hhcnQgNQ0KDQpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDcsIHJlcHIucGxvdC5oZWlnaHQgPSA0KQ0KYndwbG90KG5faW5qdXJlZH5kYXRlLi4ueWVhcnxnZW4sIGRhdGE9Ym94LCB5bGFiID0gIk51bWJlciBvZiBpbmp1cmVkIiwgeGxhYj0iIiwNCiAgICAgICBtYWluPSJEaXN0cmlidXRpb24gb2YgcGVyc29ucyBpbmp1cmVkIGluIHNwZWNpZmljIHllYXJzLCBkaXZpZGVkIGJ5IGdlbmRlciIpDQpgYGANCg0KIyMjIFRoZSBhYm92ZSBib3ggY2hhcnQgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwZW9wbGUgaW5qdXJlZCBkdXJpbmcgaW5jaWRlbnRzIGluIDIwMTQtMjAxOCBkaXZpZGVkIGludG8gZ2VuZGVyLiBXaXRoIGEgc2xpZ2h0IGFkdmFudGFnZSBvbiB0aGUgbWFsZSBzaWRlLCBpdCBoYXBwZW5lZCB0aGF0IG1vcmUgcGVvcGxlIHdlcmUgaW5qdXJlZCBkdXJpbmcgdGhlIGluY2lkZW50LiBEYXRhIGZyb20gMjAxOCBjb21lIGZyb20gdGhlIGZpcnN0IHRocmVlIG1vbnRocywgdGhhdCBpcyBmcm9tIHRoZSBmaXJzdCBxdWFydGVyLiBIb3dldmVyLCBpZiB0aGlzIHllYXIgZW5kcyB3aXRob3V0IG1ham9yIG1hc3NhY3JlcywgaXQgd2lsbCBtZWFuIGEgZGVjbGluaW5nIHRyZW5kIGFmdGVyIDIwMTcuDQoNCmBgYHtyfQ0KI0NoYXJ0IDYNCg0Ka2lsbCA8LSBndW5fdmlvbGVuY2UgJT4lIHNlbGVjdChuX2tpbGxlZCwgc3RhdGUsZ2VuZGVyKQ0Ka2lsbF9tIDwtIGZpbHRlcihraWxsLCBnZW5kZXI9PSJNYWxlIikNCmtpbGxfZiA8LSBmaWx0ZXIoa2lsbCwgZ2VuZGVyPT0iRmVtbGUiKQ0KDQpraWxsMSA8LSBhZ2dyZWdhdGUobl9raWxsZWQgfiBzdGF0ZSArIGdlbmRlciwgZGF0YSA9IGtpbGxfbSwgc3VtKQ0Ka2lsbDIgPC0gYWdncmVnYXRlKG5fa2lsbGVkIH4gc3RhdGUgKyBnZW5kZXIsIGRhdGEgPSBraWxsX2YsIHN1bSkNCmd1bnNfcmVnaXN0ZXJlZDIgPC0gZ3Vuc19yZWdpc3RlcmVkDQpuYW1lcyhndW5zX3JlZ2lzdGVyZWQyKSA8LSBjKCJpZCIsInN0YXRlIiwgIm5fZ3VucyIsIm5fZ3Vuc19wZXJfY2FwaXRhIikNCmd1bnNfcmVnaXN0ZXJlZDIkaWQgPC0gTlVMTA0KDQpraWxsX20xIDwtIG1lcmdlKGtpbGwxLCBndW5zX3JlZ2lzdGVyZWQyLCBieT0ic3RhdGUiKQ0Ka2lsbF9mMSA8LSBtZXJnZShraWxsMiwgZ3Vuc19yZWdpc3RlcmVkMiwgYnk9InN0YXRlIikNCmtpbGxfbWYgPC0gcmJpbmQoa2lsbF9tMSwga2lsbF9mMSkNCmtpbGxfbWYkZ2VuIDwtIGZhY3RvcihraWxsX21mJGdlbmRlciwgbGV2ZWxzPWMoIk1hbGUiLCJGZW1sZSIpLCBsYWJlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKQ0Ka2lsbF9tZiRnZW5kZXIgPC0gTlVMTA0Kb3B0aW9ucyhzY2lwZW49OTk5KQ0KDQpnZ3Bsb3Qoa2lsbF9tZixhZXMobl9ndW5zKjEwMDAsbl9raWxsZWQsc2l6ZT1uX2d1bnNfcGVyX2NhcGl0YSwgY29sb3VyPWdlbikpKyBnZW9tX3BvaW50KCkrDQogIGxhYnMoIHg9Ik51bWJlciBvZiBndW5zIHJlZ2lzdGVyZWQiLHk9Ik51bWJlciBvZiBraWxsZWQiLHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGd1bnMsdmljdGltcyBhbmQgZ2VuZGVyIikrIA0KICBzY2FsZV9zaXplKG5hbWU9Ik51bWJlciBvZiBndW5zIHBlciBjYXBpdGEiKSsgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZT0iR2VuZGVyIikrDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHM9Y29tbWEpDQpgYGANCg0KIyMjIFRoZSBhYm92ZSBzY2F0dGVyIHBsb3Qgc2hvd3MgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIG51bWJlciBvZiByZWdpc3RlcmVkIHdlYXBvbnMgYW5kIHRoZSBudW1iZXIgb2YgcGVvcGxlIGtpbGxlZC4gSW4gYWRkaXRpb24sIHRoZSBzaXplIG9mIHRoZSBkb3QgaXMgZXhwcmVzc2VkIGJ5IHRoZSBudW1iZXIgb2Ygd2VhcG9ucyBwZXIgb25lIGluaGFiaXRhbnQsIGFuZCB0aGUgY29sb3IgaXMgc2VwYXJhdGVkIGJ5IGdlbmRlci4gVGhlIHRlbmRlbmNpZXMgZ3Jvd2luZyBmb3IgYm90aCBzZXhlcywgaWUgd2l0aCB0aGUgaW5jcmVhc2UgaW4gdGhlIG51bWJlciBvZiByZWdpc3RlcmVkIHdlYXBvbnMsIHRoZSBudW1iZXIgb2YgcGVvcGxlIGtpbGxlZCBpcyBpbmNyZWFzaW5nLiBSYXRoZXIsIHdlIGNhbiBzYXkgdGhhdCB0aGUgbnVtYmVyIG9mIHdlYXBvbnMgcGVyIG9uZSBpbmhhYml0YW50IGhhcyBubyBlZmZlY3QuDQoNCmBgYHtyfQ0KI0NoYXJ0IDcNCg0KbGlicmFyeShwbHlyKQ0KZ2dwbG90bHkoZ3VuX3Zpb2xlbmNlICU+JSBjb3VudCgic3RhdGUiKSAgJT4lDQogICAgICAgICAgIGdncGxvdChhZXMoeD1yZW9yZGVyKHN0YXRlLCBmcmVxKSwgeT1mcmVxLCBmaWxsPWZyZXEsIHRleHQ9c3RhdGUpKSArDQogICAgICAgICAgIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JywgZmlsbD0nYmx1ZScpICsgY29vcmRfZmxpcCgpICsNCiAgICAgICAgICAgbGFicyh4PScnLCB5PSdOdW1iZXIgb2YgaW5jaWRlbnRzJywgdGl0bGUgPSAiTnVtYmVyIG9mIGluY2lkZW50cyBpbiBzcGVjaWZpYyBzdGF0ZXMiKSwNCiAgICAgICAgIHRvb2x0aXA9YygidGV4dCIsICJ5IiksIGhlaWdodCA9IDc1MCwgd2lkdGg9ODAwKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgYmFyIGNoYXJ0IHByZXNlbnRzIHRoZSBkaXN0cmlidXRpb24gb2Ygc3RhdGVzIHdpdGggdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIGluY2lkZW50cyBpbiB0aGUgcGVyaW9kIDIwMTQtMjAxOC4gVGhlIElsbGlub2lzIHN0YXRlIGFwcGVhcnMgYWdhaW4sIHdoZXJlIHRoZSBudW1iZXIgb2YgcmVnaXN0ZXJlZCB3ZWFwb25zIHdhcyBub3QgaW5jbHVkZWQgaW4gdGhlIFRvcCA4IGxpc3QuIEluIGFkZGl0aW9uLCB0aGlzIHN0YXR1cyBpcyBwbGFjZWQgb24gdGhlIGZpcnN0IHBsYWNlIGluIHRoZSBsaXN0LCBhbmQgaW4gdGhlIG51bWJlciBvZiBpbmp1cmVkIHBlb3BsZS4gSW4gdGhlIG5leHQgcGFydCB3ZSB3aWxsIGNoZWNrIGlmIGl0IGlzIGFmZmVjdGVkIGJ5IG9uZSBvZiB0aGUgbGFyZ2VzdCBjaXRpZXMgaW4gdGhlIFVTQSAtIENoaWNhZ28uIE9uIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiBDYWxpZm9ybmlhLCBGbG9yaWRhLCBUZXhhcyBhbmQgT2hpby4gVGhlIGZld2VzdCBpbmNpZGVudHMgd2VyZSByZWNvcmRlZCBpbiBIYXdhaWkuIEluIGFkZGl0aW9uLCB3ZSB3aWxsIGNoZWNrIHdoZXRoZXIgdGhpcyBpcyByZWxhdGVkIHRvIHRoZSBudW1iZXIgb2YgdGhlIGdpdmVuIHN0YXRlLg0KDQpgYGB7cn0NCiNDaGFydCA4DQoNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gNSwgcmVwci5wbG90LmhlaWdodCA9IDUpDQphZ2EgPC0gYWdncmVnYXRlKG5faW5qdXJlZCB+IHN0YXRlICsgZGF0ZS4uLnllYXIsIGRhdGEgPSBndW5fdmlvbGVuY2UsIHN1bSkNCm5hbWVzKGFnYSkgPC0gYygiU3RhdGUiLCAiRGF0ZSIsICJWYWx1ZSIpDQphZ2EkRGF0ZSA8LSBmb3JtYXQoYXMuRGF0ZShhZ2EkRGF0ZSwgZm9ybWF0ID0gIiVZLSVtLSVkIiksICIlWSIpDQphZ2EgPC0gYWdhW29yZGVyKGFnYSRWYWx1ZSwgZGVjcmVhc2luZyA9IFRSVUUpLF0NCg0KbW0xIDwtIGZpbHRlcihhZ2EsIFN0YXRlID09IGMoIklsbGlub2lzIikgKQ0KbW0yIDwtIGZpbHRlcihhZ2EsIFN0YXRlID09IGMoIkNhbGlmb3JuaWEiKSApDQptbTMgPC0gZmlsdGVyKGFnYSwgU3RhdGUgPT0gYygiRmxvcmlkYSIpICkNCm1tNCA8LSBmaWx0ZXIoYWdhLCBTdGF0ZSA9PSBjKCJUZXhhcyIpICkNCm1tNSA8LSBmaWx0ZXIoYWdhLCBTdGF0ZSA9PSBjKCJOZXcgWW9yayIpICkNCm1tNiA8LSBmaWx0ZXIoYWdhLCBTdGF0ZSA9PSBjKCJPaGlvIikgKQ0KDQptbTcgPC0gcmJpbmQobW0xLG1tMixtbTMsbW00LG1tNSxtbTYpDQoNCm1tOCA8LSBmaWx0ZXIobW03LCBEYXRlIT0yMDE4KQ0KDQpnZ3Bsb3QobW04LGFlcyhTdGF0ZSxWYWx1ZSxmaWxsPURhdGUpKSsNCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPSJkb2RnZSIpKw0KICBnZ3RpdGxlKCJOdW1iZXIgb2YgaW5qdXJlZCBpbiBzcGVjaWZpYyBzdGF0ZXMgKHllYXJzIDIwMTQtMjAxNykiKSArIA0KICBsYWJzKHg9IiIseT0iTnVtYmVyIG9mIGluanVyZWQiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iIiwgbGFiZWxzPWMoIjIwMTQiLCIyMDE1IiwiMjAxNiIsIjIwMTciKSkrDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNzAwMCxieT01MDApKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgYmFyIGNoYXJ0IHNob3dzIHRoZSBudW1iZXIgb2YgcGVvcGxlIGluanVyZWQgaW4gaW5kaXZpZHVhbCBzdGF0ZXMsIHRoaXMgdGltZSBpbGx1c3RyYXRpbmcgdGhlIHNpdHVhdGlvbiBvdmVyIHRoZSB5ZWFycyAyMDE0LTIwMTcuIEluIElsbGlub2lzLCB3aGVyZSB0aGUgaGlnaGVzdCBudW1iZXIgb2YgaW5jaWRlbnRzIG9jY3VyIGFuZCB0aGUgaGlnaGVzdCBudW1iZXIgb2YgaW5qdXJlZCBwZW9wbGUsIGluIDIwMTcgdGhlIG51bWJlciBvZiBpbmNpZGVudHMgbm90aWNlYWJseSBkZWNyZWFzZWQuIFNpbWlsYXJseSwgdGhlIHNpdHVhdGlvbiBpbiBvdGhlciBzdGF0ZXMsIG9ubHkgQ2FsaWZvcm5pYSBhbmQgT2hpbywgcmVjb3JkZWQgYSBzbGlnaHQgaW5jcmVhc2UuDQoNCmBgYHtyfQ0KI0NoYXJ0IDkNCg0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSA5LCByZXByLnBsb3QuaGVpZ2h0ID0gNikNCmJuIDwtIHRhcHBseShndW5fdmlvbGVuY2Ukbl9pbmp1cmVkLCBndW5fdmlvbGVuY2UkY2l0eSwgc3VtKQ0KbW1tID0gbWVsdChibikNCg0KbmFtZXMobW1tKSA8LSBjKCJjaXR5IiwidmFsdWUiKQ0KDQpjIDwtIG1lcmdlKG1tbSxVU0FfcG9wdWxhdGlvbiwgYnk9ImNpdHkiKQ0KYzEgPC0gZmlsdGVyKGMsIHZhbHVlPjE1MDApDQpuYW1lcyhjMSkgPC0gYygiY2l0eSIsICJ2YWx1ZSIsICJyYW5rIiwgInBvcHVsYXRpb24iLCAiZGVuc2l0eSIpDQoNCnBhcihtYWkgPSBjKDEsIDEsIDEsIDEpLCBvbWkgPSBjKDAsIDAsIDAsIDApKQ0KDQpiYXJwbG90Lnh0aWNrcyA8LSBiYXJwbG90KGMxJHBvcHVsYXRpb24sIGNvbCA9ICJsaWdodGJsdWUiLCBheGVzPUZBTFNFLCB4bGltPWMoMCw3KSx5bGltID0gYygwLDI4MDAwMDApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJDaXRpZXMiLCB5bGFiID0gIlBvcHVsYXRpb24iLCB4cGQgPSBGQUxTRSkgDQoNCmJveCgpDQpheGlzKDEsIGF0ID0gYmFycGxvdC54dGlja3MsIGxhYmVscyA9IGMoIkJhbHRpbW9yZSIsIkNoaWNhZ28iLCJNZW1waGlzIiwiTWlsd2F1a2VlIiwiTmV3IE9ybGVhbnMiLCJQaGlsYWRlbHBoaWEiKSkNCmF4aXMoMiwgYXQgPSBzZXEoZnJvbSA9IDAsIHRvID0gMjgwMDAwMCwgYnkgPSAyMDAwMDApLCBjb2wgPSAibGlnaHRibHVlIiwgbHdkID0gMikNCg0KcGFyKG5ldyA9IFRSVUUpDQpwbG90KGJhcnBsb3QueHRpY2tzLCBjMSR2YWx1ZSwgdHlwZSA9ICJiIiwgbHdkID0gMiwgY29sID0gInJlZCIsIHBjaCA9IDE2LCBjZXggPSAxLjUsIA0KICAgICB4bGFiID0gIiIsIGFubiA9IEZBTFNFLCBheGVzID0gRkFMU0UsIHhsaW09YygwLDcpLCB5bGltID0gYygwLCAxMTAwMCksIA0KICAgICB5YXhzID0gImkiKQ0Kd2l0aChjMVssXSwgdGV4dChjMSR2YWx1ZSwgbGFiZWxzID1jMVssMl0sIHBvcyA9IDMpKQ0KDQpheGlzKDQsIGNvbCA9ICJyZWQiLCBhdCA9IHNlcShmcm9tID0gMCwgdG8gPSAxMjAwMCwgYnkgPSAyMDAwKSAsIGx3ZCA9IDIpDQptdGV4dCgiTnVtYmVyIG9mIGluanVyZWQiLCBzaWRlID0gNCwgbGluZSA9IDMpDQoNCnRpdGxlKCJQb3B1bGF0aW9uICYgTnVtYmVyIG9mIGluanVyZWQiKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgYmFyLWxpbmVhciBkaWFncmFtIHNob3dzIHRoZSBkZXBlbmRlbmNlIG9mIHRoZSBwb3B1bGF0aW9uIG9mIGEgZ2l2ZW4gc3RhdGUsIGFuZCB0aGUgbnVtYmVyIG9mIGluanVyZWQgcGVvcGxlLiBUaGVyZSBpcyBhIGNvcnJlbGF0aW9uIHRoYXQgdGhlIGxhcmdlciB0aGUgcG9wdWxhdGlvbiwgdGhlIGhpZ2hlciB0aGUgbnVtYmVyIG9mIHBlb3BsZSBpbmp1cmVkLiBJbiBOZXcgT3JsZWFucywgZGVzcGl0ZSB0aGUgcG9wdWxhdGlvbiBvZiAyLzMgb2YgTWVtcGhpcyBwb3B1bGF0aW9uLCB0aGUgbnVtYmVyIG9mIGluanVyZWQgcGVvcGxlIHdhcyBldmVuIGhpZ2hlciBieSB+IDE1JS4NCg0KYGBge3J9DQojQ2hhcnQgMTANCg0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSA0LCByZXByLnBsb3QuaGVpZ2h0ID0gNCkNCmduIDwtIHRhcHBseShndW5fdmlvbGVuY2Ukbl9raWxsZWQsIGd1bl92aW9sZW5jZSRkYXRlLi4ueWVhciwgc3VtKQ0Kbm5uMSA9IG1lbHQoZ24pDQpuYW1lcyhubm4xKSA8LSBjKCJEYXRlIiwgIlZhbHVlIikNCm5ubjEkRGF0ZSA8LSBmb3JtYXQoYXMuRGF0ZShubm4xJERhdGUsIGZvcm1hdCA9ICIlWS0lbS0lZCIpLCAiJVkiKQ0Kbm5uIDwtIGZpbHRlcihubm4xLCBEYXRlIT0yMDE4KQ0KbXlfdHMgPSB0cyhubm4sIHN0YXJ0ID0gMjAxNCwgZW5kID0gMjAxNywgZnJlcXVlbmN5ID0gMSkNCmtvbCA8LSBteV90c1ssMl0NCg0KeHlwbG90KGtvbCxwYW5lbCA9IHBhbmVsLnh5YXJlYSwgb3JpZ2luID0gMCx4bGFiPSJZZWFyIiwNCiAgICAgICB5bGFiPSJOdW1iZXIgb2Yga2lsbGVkIixtYWluPSJOdW1iZXIgb2Yga2lsbGVkIGluIHRoZSBVU0EgeWVhciBvbiB5ZWFyIiwNCiAgICAgICBzY2FsZXM9bGlzdCh4PWxpc3QoYXQ9c2VxKDIwMTQsIDIwMTcsIDEpKSx5PWxpc3QoYXQ9c2VxKDAsIDE2NTAwLCA2MDApKSkpDQpgYGANCg0KIyMjIFRoZSBhYm92ZSBjaGFydCBpbGx1c3RyYXRpbmcgdGhlIHNpdHVhdGlvbiBpbiAyMDE0LTIwMTcgaW5kaWNhdGVzIHRoYXQgd2UgaGF2ZSBhbiBpbmNyZWFzaW5nIHRlbmRlbmN5IG9mIHRoZSBudW1iZXIgb2YgcGVvcGxlIGtpbGxlZC4gQmVjYXVzZSB0aGUgZGF0YSBmcm9tIDIwMTggY29tZSBmcm9tIHRoZSBmaXJzdCBxdWFydGVyLCBzcGVjdWxhdGlvbnMgcmVnYXJkaW5nIHRoZSBjb250aW51aW5nIHVwd2FyZCB0cmVuZCB3aWxsIGJlIGNhcnJpZWQgb3V0IGxhdGVyLg0KDQoNCmBgYHtyfQ0KI0NoYXJ0IDEyDQoNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gNywgcmVwci5wbG90LmhlaWdodCA9IDYpDQpndW5fdmlvbGVuY2UkZGF0ZUNoYXIgPC0gYXMuRGF0ZShndW5fdmlvbGVuY2UkZGF0ZSkNCg0KZ3VuX3Zpb2xlbmNlJGRhdGVDaGFyIDwtIHltZChndW5fdmlvbGVuY2UkZGF0ZUNoYXIpDQpzdHIoZ3VuX3Zpb2xlbmNlJGRhdGVDaGFyKQ0KDQpndW5fdmlvbGVuY2UkcXUgPC0gcXVhcnRlcihndW5fdmlvbGVuY2UkZGF0ZUNoYXIpDQoNCmd1bl92aW9sZW5jZSR5ciA8LSB5ZWFyKGd1bl92aW9sZW5jZSRkYXRlQ2hhcikNCg0KZ3VuX3Zpb2xlbmNlMiA8LSBndW5fdmlvbGVuY2VbLDI3OjI4XQ0KDQpxMSA8LSBjb3VudChndW5fdmlvbGVuY2UyLCBjKCJxdSIsICJ5ciIpKSU+JQ0KICAgIGdncGxvdChhZXMoeD1hcy5mYWN0b3IocXUpLCB5PWZyZXEpKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JywgZmlsbD0nYmx1ZScpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKyBmYWNldF9ncmlkKC5+eXIpICsgbGFicyh4PSdRdWFydGVyJywgeT0nTnVtYmVyIG9mIGluY2lkZW50cycpDQoNCnEyIDwtIGNvdW50KGd1bl92aW9sZW5jZTIsIGMoInF1IiwgInlyIikpJT4lIGZpbHRlcihxdT09MSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9YXMuZmFjdG9yKHlyKSwgeT1mcmVxKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScsIGZpbGw9J2JsdWUnKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsgbGFicyh4PSdJbmNpZGVudHMgaW4gUTEgb2YgZWFjaCB5ZWFyJywgeT0nTnVtYmVyIG9mIGluY2lkZW50cycpDQoNCmdyaWQuYXJyYW5nZShxMSwgcTIpDQpgYGANCg0KIyMjIFRoZSBhYm92ZSBncmFwaHMgd2lsbCBhcHByb3hpbWF0ZSB0aGUgYW5zd2VyIHJlZ2FyZGluZyB0aGUgdXB3YXJkIHRyZW5kIGluIHRoZSBudW1iZXIgb2YgaW5jaWRlbnRzLiBUaGVyZSBzZWVtcyB0byBiZSBzb21lICJzZWFzb25hbGl0eSIgaW4gUTEgYW5kIFE0LCB3aGljaCBnZW5lcmFsbHkgaGF2ZSBhIHNtYWxsZXIgbnVtYmVyIG9mIGluY2lkZW50cyB0aGFuIGluIFEyIGFuZCBRMy4gVGhlIHNlY29uZCBjaGFydCBzaG93cyB0aGF0IGluIFExIDIwMTggdGhlcmUgd2VyZSBmZXdlciBpbmNpZGVudHMgdGhhbiBpbiBRMSAyMDE3LiBJdCBjYW4gYmUgY29uc2lkZXJlZCBhIHF1aXRlIHBvc2l0aXZlIHNpZ25hbC4gSG93ZXZlciwgaXQgc2hvdWxkIGJlIHJlbWVtYmVyZWQgdGhhdCB0aGlzIG51bWJlciBpcyBzdGlsbCB2ZXJ5IGhpZ2ggY29tcGFyZWQgdG8gb3RoZXIgY291bnRyaWVzIChyZWxhdGl2ZWx5KS4gDQojIyMgUXVhcnRlcmx5IGFuYWx5c2lzIHNob3dzIHRoYXQgbW9yZSBpbmNpZGVudHMgb2NjdXIgaW4gd2FybWVyIHNwcmluZyBhbmQgc3VtbWVyIHNlYXNvbnMuIEl0IHNlZW1zIHRoYXQgaXQgaXMgd29ydGggdGFraW5nIGEgY2xvc2VyIGxvb2sgYXQgdGhpcy4gSW4gb3JkZXIgdG8gY29tcGFyZSBtb250aHMsIEkgZXhjbHVkZSAyMDE4IGJlY2F1c2UgaXQgaXMgbm90IGNvbXBsZXRlLg0KDQpgYGB7cn0NCiNDaGFydCAxMw0KDQpndW5fdmlvbGVuY2UkbW8gPC0gbHVicmlkYXRlOjptb250aChndW5fdmlvbGVuY2UkZGF0ZUNoYXIsIGxhYmVsPVRSVUUpDQpnZ3Bsb3RseShndW5fdmlvbGVuY2UgJT4lIGZpbHRlcih5ciE9YygyMDEzLCAyMDE4KSkgJT4lIGNvdW50KCJtbyIpICU+JQ0KICAgICAgICAgICAgICAgICAgIGdncGxvdChhZXMoeD1tbywgeT1mcmVxKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScsIGZpbGw9J2JsdWUnKSArDQogICAgICAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKw0KICAgICAgICAgICAgICAgICAgIGxhYnMoeD0nTW9udGgnLCB5PSdOdW1iZXIgb2YgaW5jaWRlbnRzJywgdGl0bGU9J0luY2lkZW50cyBieSBNb250aCcpKQ0KYGBgDQoNCiMjIyBUaGUgbW9zdCB2aXNpYmxlICJzZWFzb25hbGl0eSIgaXMgdGhlIG9ic2VydmF0aW9uIHRoYXQgZmV3ZXIgaW5jaWRlbnRzIGhhcHBlbiBpbiBjb29sZXIgbW9udGhzLiBOb3ZlbWJlciwgRGVjZW1iZXIgYW5kIEZlYnJ1YXJ5IGlzIDMgbW9udGhzIHdpdGggdGhlIGxvd2VzdCBudW1iZXIgb2YgaW5jaWRlbnRzIChGZWJydWFyeSwgb2YgY291cnNlLCBvbmx5IDI4IGRheXMpLiBUaGUgb25seSBleGNlcHRpb24gaXMgSmFudWFyeSwgd2hpY2ggaXMgd29ydGggaW52ZXN0aWdhdGluZyBsYXRlci4gUHJvYmFibHkgaW5jaWRlbnRzIGR1cmluZyB0aGUgTmV3IFllYXIgcGVyaW9kIGNvbnRyaWJ1dGUgdG8gdGhlIGZhY3QgdGhhdCBKYW51YXJ5IGhhcyBhIGxhcmdlIG51bWJlciBvZiBpbmNpZGVudHMuDQojIyMgVGhlIHNlY29uZCBwZWFrIGlzIHRoZSBwZXJpb2QgSnVseSAvIEF1Z3VzdC4gUHJvYmFibHkgYmVjYXVzZSBtYW55IHBlb3BsZSBnbyBvbiB2YWNhdGlvbiBkdXJpbmcgdGhpcyBwZXJpb2QuDQoNCmBgYHtyfQ0KI0NoYXJ0IDE0DQoNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gNiwgcmVwci5wbG90LmhlaWdodCA9IDQpDQpndW5fdmlvbGVuY2UkZGEgPC0gZGF5KGd1bl92aW9sZW5jZSRkYXRlQ2hhcikNCmd1bl92aW9sZW5jZSA8LSBndW5fdmlvbGVuY2UgJT4lIG11dGF0ZShkYXRlQ2hhcjI9cGFzdGUobW8sIGRhKSkNCmphbiA8LSBndW5fdmlvbGVuY2UgJT4lIGZpbHRlcih5ciE9YygiMjAxMyIsICIyMDE4IikpICU+JSBjb3VudCgiZGF0ZUNoYXIyIikgJT4lIHRvcF9uKDEwKSAlPiUgYXJyYW5nZShkZXNjKGZyZXEpKQ0KZ2dwbG90KGphbixhZXMoeD1yZW9yZGVyKGRhdGVDaGFyMiwtZnJlcSkseT1mcmVxKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb249ImRvZGdlIiwgZmlsbD0iYmx1ZSIpICsgDQogIGxhYnMoeD0iVGhlIG1vc3QgY29tbW9uIGRheXMiLHk9Ik51bWJlciBvZiBpbmNpZGVudHMiLCB0aXRsZT0iVGhlIG1vc3QgZGFuZ2Vyb3VzIGRheXMiKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgbnVtYmVycyBhcmUgaW4gZmFjdCBzdW1zIG9mIDQgZGF0ZXMsIGJlY2F1c2UgdGhleSBhcmUgc3VtbWVkIHVwIGZvciA0IHllYXJzIChmb3IgZXhhbXBsZTogMS0xLTIwMTQsIDEtMS0yMDE1LCAxLTEtMjAxNiwgMS0xLTIwMTcpLiBXaXRoIGFuIGF2ZXJhZ2Ugb2YgNjE4ICh0aGUgdG90YWwgbnVtYmVyIG9mIGluY2lkZW50cyBpbiAyMDE0LTIwMTcgZGl2aWRlZCBpbnRvIDM2NSBjYWxlbmRhciBkYXlzLCAyMjU1OTgvMzY1KSwgdGhlcmUgYXJlIG5vdCBtYW55IGRhdGVzIHRoYXQgcmVhbGx5IHN0b29kIG91dC4gTW9zdCBvZiB0aGUgZGF0ZXMgaW4gdGhlIHRvcCB0ZW4gc2VlbSAib3JkaW5hcnkiIGRheXMgaW4gSnVseSAvIEF1Z3VzdC4gSG93ZXZlciwgSmFudWFyeSAxIGFjdHVhbGx5IHBhcnRpYWxseSBleHBsYWlucyB0aGUgaGlnaGVyIGluY2lkZW50cyBpbiBKYW51YXJ5LiBJbiBhZGRpdGlvbiwgaW5kZXBlbmRlbmNlIGRheSAoSnVseSA0KSBpcyBhbHNvIGRhbmdlcm91cyB3aGVuIGl0IGNvbWVzIHRvIHdlYXBvbi1yZWxhdGVkIGluY2lkZW50cy4gSSBzdXBwb3NlIHRoZSBoaWdoIG51bWJlciBvZiBKdWx5IDUgaXMgZHVlIHRvIHBlb3BsZSBjb250aW51aW5nIHRoZWlyIGNlbGVicmF0aW9uIGFmdGVyIG1pZG5pZ2h0Lg0KDQpgYGB7cn0NCiNDaGFydCAxNQ0KDQppbmNpZGVudHNCeVN0YXRlIDwtIGd1bl92aW9sZW5jZSAlPiUgY291bnQoInN0YXRlIikgDQppbmNpZGVudHNCeVN0YXRlIDwtIGxlZnRfam9pbihpbmNpZGVudHNCeVN0YXRlLCBzdGF0ZV9wb3B1bGF0aW9uLCBieT0ic3RhdGUiKQ0KaW5jaWRlbnRzQnlTdGF0ZVssM10gPC0gTlVMTA0KaW5jaWRlbnRzQnlTdGF0ZSRQZXIxMDAwMDAgPC0gcm91bmQoKGluY2lkZW50c0J5U3RhdGUkZnJlcS9pbmNpZGVudHNCeVN0YXRlJHBvcHVsYXRpb24pKjEwMDAwMCkNCg0KZ2dwbG90bHkoaW5jaWRlbnRzQnlTdGF0ZSU+JSBmaWx0ZXIoc3RhdGUhPSJEaXN0cmljdCBvZiBDb2x1bWJpYSIpICU+JQ0KICAgICAgICAgICAgICAgICAgIGdncGxvdChhZXMoeD1yZW9yZGVyKHN0YXRlLCBQZXIxMDAwMDApLCB5PVBlcjEwMDAwMCwgZmlsbD1QZXIxMDAwMDAsIHRleHQ9c3RhdGUpKSArDQogICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGNvb3JkX2ZsaXAoKSArDQogICAgICAgICAgICAgICAgICAgbGFicyh4PSIiLHk9IiIsIHRpdGxlPSdJbmNpZGVudHMgcGVyIDEwMCwwMDAgaW5oYWJpdGFudHMnKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ5ZWxsb3ciLCBoaWdoPSJyZWQiKSArDQogICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogICAgICAgICAgICAgICAgIHRvb2x0aXA9YygidGV4dCIsICJ5IiksIGhlaWdodCA9IDc1MCwgd2lkdGg9ODAwKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgZ3JhcGggc2hvd3MgdGhhdCBlbnJpY2hlZCBkYXRhLCB3aGljaCBhcmUgcmVsYXRlZCB0byB0aGUgcG9wdWxhdGlvbiBvZiBlYWNoIHN0YXRlLCBwcmVzZW50IGEgdmVyeSBkaWZmZXJlbnQgcGljdHVyZS4gQXMgdGhlIG51bWJlciBvZiBpbmNpZGVudHMgaXMgcmVsYXRlZCB0byB0aGUgc2l6ZSBvZiB0aGUgcG9wdWxhdGlvbiwgdGhlc2UgbnVtYmVycyBub3cgcmVwcmVzZW50IHRoZSAicmVhbCIgdGhyZWF0IGxldmVsIG9mIHRoZSBvcGVyYXRpb24gb2YgdGhlIHdlYXBvbi4gVG8gc2hvdyBpdCB2aXN1YWxseSwgSSB1c2VkIGNvbG9yIGNvZGVzLiBSZWQgaW5kaWNhdGVzIGEgaGlnaCBsZXZlbCBvZiBkYW5nZXIgaW4gdGVybXMgb2YgdGhlIHJlbGF0aXZlIG51bWJlciBvZiBpbmNpZGVudHMsIGFuZCB5ZWxsb3cgaW5kaWNhdGVzIHRoYXQgdGhlIHN0YXRlIGlzIHJlbGF0aXZlbHkgc2FmZS4NCiMjIyBBbGFza2EsIExvdWlzaWFuYSBhbmQgRGVsYXdhcmUgbm93IHNob3cgdGhlIGhpZ2hlc3QgcmVsYXRpdmUgbnVtYmVycyBvZiBpbmNpZGVudHMuIEhhd2FpaSBzZWVtcyB0byBiZSB0aGUgc2FmZXN0IGNvdW50cnkgdG8gbGl2ZSBpbiwgYW5kIHRoZSBsYXJnZSBzdGF0ZSBvZiBDYWxpZm9ybmlhIGZhbGxzIGZyb20gdGhlIHNlY29uZCBzdGF0ZSBpbiB0ZXJtcyBvZiBhYnNvbHV0ZSBpbmNpZGVudHMgdG8gYSBsb3cgcG9zaXRpb24sIGFkanVzdGVkIGZvciBhIGxhcmdlIHBvcHVsYXRpb24uDQoNCmBgYHtyfQ0KI0NoYXJ0IDE2IE51bWJlciBvZiBpbmNpZGVudHMgcGVyIDEwMCwwMDAgaW5oYWJpdGFudHMgaW4gc3BlY2lmaWMgc3RhdGVzDQoNCmxpYnJhcnkoaHR0cikNCnNldHdkKCIuIikNCnVybCA8LSAiaHR0cHM6Ly9naXRodWIuY29tL21hbGV3aWN6Sy9EYXRhLVNjaWVuY2Utb3ZlcmFsbC1wcm9qZWN0cy9ibG9iL21hc3Rlci9NYXBzRGF0YS9NYXBzLnppcD9yYXc9dHJ1ZSINCmRvd25sb2FkLmZpbGUodXJsLCBkZXN0PSJNYXBzLnppcCIsIG1vZGU9IndiIikgDQp1bnppcCgiTWFwcy56aXAiLGV4ZGlyPSIuL01hcHMiKQ0KZGlyKCIuL01hcHMiKQ0KbGlicmFyeShyZ2RhbCkNCg0Kc3RhdGVzIDwtIHJlYWRPR1IoZHNuID0gIi4vTWFwcyIsIA0KICAgICAgICAgICAgICAgICAgbGF5ZXIgPSAiY2JfMjAxN191c19zdGF0ZV81MDBrIiwgDQogICAgICAgICAgICAgICAgICBlbmNvZGluZyA9ICJVVEYtOCIpDQphZGRQZXIxMDBrIDwtIGRhdGEuZnJhbWUoaWQ9c3RhdGVzJEdFT0lELCBuYW1lPXN0YXRlcyROQU1FKQ0KbmFtZXMoYWRkUGVyMTAwaykgPC0gYygiaWQiLCAic3RhdGUiKQ0KYWRkUGVyMTAwayA8LSBsZWZ0X2pvaW4oYWRkUGVyMTAwaywgaW5jaWRlbnRzQnlTdGF0ZSAlPiUgc2VsZWN0KHN0YXRlLCBQZXIxMDAwMDApLCBieT0ic3RhdGUiKQ0KYWRkUGVyMTAwayRQZXIxMDAwMDBbaXMubmEoYWRkUGVyMTAwayRQZXIxMDAwMDApXSA8LSAwDQpzdGF0ZXMkcGVyMTAwayA8LSBhZGRQZXIxMDBrJFBlcjEwMDAwMA0KDQpiaW5zIDwtIGMoMCwgNTAsIDc1LCAxMDAsIDE1MCwgSW5mKQ0KcGFsIDwtIGNvbG9yQmluKCJCbHVlcyIsIGRvbWFpbiA9IHN0YXRlcyRwZXIxMDBrLCBiaW5zID0gYmlucykNCg0Kc3RhdGVfcG9wdXAgPC0gcGFzdGUwKCI8c3Ryb25nPlN0YXRlOiA8L3N0cm9uZz4iLCANCiAgICAgICAgICAgICAgICAgICAgICBzdGF0ZXMkTkFNRSwgDQogICAgICAgICAgICAgICAgICAgICAgIjxicj48c3Ryb25nPkluY2lkZW50cyBwZXIgMTAwLDAwMCBpbmhhYml0YW50cyA8L3N0cm9uZz4iLCANCiAgICAgICAgICAgICAgICAgICAgICBzdGF0ZXMkcGVyMTAwaykgJT4lIGxhcHBseShodG1sdG9vbHM6OkhUTUwpDQoNCmxlYWZsZXQoZGF0YSA9IHN0YXRlcykgJT4lDQogIHNldFZpZXcobG5nPS05NiwgbGF0PTM3LjgsIHpvb209MykgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMoIk1hcEJveCIsIG9wdGlvbnMgPSBwcm92aWRlclRpbGVPcHRpb25zKGlkID0gIm1hcGJveC5saWdodCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY2Vzc1Rva2VuID0gU3lzLmdldGVudignTUFQQk9YX0FDQ0VTU19UT0tFTicpKSkgJT4lDQogIGFkZFBvbHlnb25zKA0KICAgIGZpbGxDb2xvciA9IH5wYWwocGVyMTAwayksDQogICAgd2VpZ2h0ID0gMiwNCiAgICBvcGFjaXR5ID0gMSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoDQogICAgICB3ZWlnaHQgPSA1LA0KICAgICAgY29sb3IgPSAiIzY2NiIsDQogICAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgbGFiZWwgPSBzdGF0ZV9wb3B1cCwNCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwNCiAgICAgIHRleHRzaXplID0gIjE1cHgiLA0KICAgICAgZGlyZWN0aW9uID0gImF1dG8iKSkgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5wZXIxMDBrLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9ICJJbmNpZGVudHMiLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCmBgYA0KDQojIyMgVGhlIGFib3ZlIG1hcCBwcmVzZW50cyBkYXRhIG9uIHRoZSBudW1iZXIgb2YgaW5jaWRlbnRzIHBlciAxMDAsMDAwIGluaGFiaXRhbnRzLiBUaGUgYWJvdmUgZGF0YSBoYXMgYWxyZWFkeSBiZWVuIGRlc2NyaWJlZCBpbiB0aGUgcHJldmlvdXMgcGFydCBvZiB0aGUgYW5hbHlzaXMuDQoNCmBgYHtyfQ0KI0NoYXJ0IDE3IEluY2lkZW50cyB3aXRoIGhpZ2hlc3QgbnVtYmVycyBvZiB2aWN0aW1zDQoNClRvcDEwIDwtIGd1bl92aW9sZW5jZSAlPiUgc2VsZWN0KGRhdGVDaGFyLCBuX2tpbGxlZCwgbl9pbmp1cmVkLCBuX3ZpY3RpbXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25fZGVzY3JpcHRpb24sIGNpdHksIHN0YXRlLCBsYXRpdHVkZSwgbG9uZ2l0dWRlKSANCm5hbWVzKFRvcDEwKSA8LSBjKCJEYXRlIiwgIktpbGxlZCIsICJJbmp1cmVkIiwgIlZpY3RpbXMiLCAiTG9jYXRpb24iLCAiQ2l0eSIsICJTdGF0ZSIsDQogICAgICAgICAgICAgICAgICAibGF0aXR1ZGUiLCJsb25naXR1ZGUiKQ0KdG9vcDEwIDwtIFRvcDEwICU+JSBhcnJhbmdlKGRlc2MoVmljdGltcykpICU+JSB0b3BfbihuPTEzLCB3dD1WaWN0aW1zKQ0KDQpUb3BNYXAgPC0gdG9vcDEwICU+JSBzZWxlY3QobGF0aXR1ZGUsIGxvbmdpdHVkZSwgVmljdGltcywgQ2l0eSwgTG9jYXRpb24pDQoNCmxhYmVscyA8LSBwYXN0ZTAoIjxzdHJvbmc+Q2l0eTogPC9zdHJvbmc+IiwgVG9wTWFwJENpdHksIA0KICAgICAgICAgICAgICAgICAiPGJyPjxzdHJvbmc+TG9jYXRpb246IDwvc3Ryb25nPiIsIFRvcE1hcCRMb2NhdGlvbiwNCiAgICAgICAgICAgICAgICAgIjxicj48c3Ryb25nPlZpY3RpbXMgPC9zdHJvbmc+IiwgVG9wTWFwJFZpY3RpbXMpICU+JSBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQ0KDQpsZWFmbGV0KFRvcE1hcCkgJT4lDQogIHNldFZpZXcobG5nPS05NiwgbGF0PTM3LjgsIHpvb209NCkgJT4lDQogIGFkZFRpbGVzKCkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2Vycyh+bG9uZ2l0dWRlLCB+bGF0aXR1ZGUsIGNvbG9yID0gImJsdWUiLCByYWRpdXM9fnNxcnQoVmljdGltcyksIGxhYmVsID0gbGFiZWxzKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgbWFwIHByZXNlbnRzIGRhdGEgb24gcGxhY2VzIHdoZXJlIGluY2lkZW50cyB3aXRoIHRoZSBsYXJnZXN0IG51bWJlciBvZiBpbmp1cmVkIHBlcnNvbnMgb2NjdXJyZWQuIFZpc2libGUgYSBsYXJnZSBudW1iZXIgb2YgcG9pbnRzIGluIFRleGFzLCBDYWxpZm9ybmlhIGFuZCBGbG9yaWRhLg0KDQpgYGB7cn0NCiNDaGFydCAxOA0KDQpndW5fdmlvbGVuY2UkaW5jaWRlbnRfY2hhcmFjdGVyaXN0aWNzIDwtIGdzdWIoIlxcfFxcfCIsICJ8IiwgZ3VuX3Zpb2xlbmNlJGluY2lkZW50X2NoYXJhY3RlcmlzdGljcykNCg0KSW5jQ2hhcmFjIDwtIGNTcGxpdChndW5fdmlvbGVuY2UgJT4lIA0KICAgICAgICAgICAgc2VsZWN0KHN0YXRlLCBjaXR5LCBpbmNpZGVudF9jaGFyYWN0ZXJpc3RpY3MpLCANCiAgICAgICAgICAgICdpbmNpZGVudF9jaGFyYWN0ZXJpc3RpY3MnLCBzZXAgPSAgJ3wnLCBkaXJlY3Rpb249ImxvbmciKQ0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSAyMCwgcmVwci5wbG90LmhlaWdodCA9IDcpDQpJbmNDaGFyYWMgJT4lIGNvdW50KCJpbmNpZGVudF9jaGFyYWN0ZXJpc3RpY3MiKSAlPiUgdG9wX24oMzAsIHd0PWZyZXEpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihpbmNpZGVudF9jaGFyYWN0ZXJpc3RpY3MsIGZyZXEpLCB5PWZyZXEpLGhlaWdodCA9IDc1MCwgd2lkdGg9MTUwMCkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScsIGZpbGw9J3JlZCcpICsNCiAgY29vcmRfZmxpcCgpICsgbGFicyh4PSdJbmNpZGVudCBDYXRlZ29yeScsIHk9IiIsdGl0bGU9Ik51bWJlciBvZiBpbmNpZGVudHMiKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgY2hhcnQgc2hvd3MgdGhlIGNpcmN1bXN0YW5jZXMgb2YgdGhlIGluY2lkZW50LiBPbiB0aGUgZmlyc3QgdHdvIHBsYWNlcyBhbmQgb24gdGhlIGZvdXJ0aCB0aGVyZSBhcmUgcG9zaXRpb25zIHJlbGF0ZWQgdG8gc2hvb3RpbmcuIFRoZWlyIHN1bSByZXN1bHRzIGluIGEgc2lnbmlmaWNhbnQgcGFydCBvZiBpbmNpZGVudHMuIEl0IHNob3VsZCBiZSBub3RlZCB0aGF0IGluIHRoaXJkIHBsYWNlIHdhcyB0aGUgaXRlbSB3aXRoIHRoZSBkZXNjcmlwdGlvbiAiTm9uLVNob290aW5nIGluY2lkZW50Iiwgd2hpY2ggbWF5IG1lYW4gZmlnaHRzLCB0aGUgdXNlIG9mIHdoaXRlIG9yIG90aGVyIG5vbi1mbGFtbWFibGUgd2VhcG9ucy4NCg0KYGBge3J9DQojQ2hhcnQgMTkNCg0KZ3VuX3Zpb2xlbmNlJGxvY2F0aW9uX2Rlc2NyaXB0aW9uIDwtIGdzdWIoIk1jRG9uYWxkcyIsICJNY0RvbmFsZCdzIiwgZ3VuX3Zpb2xlbmNlJGxvY2F0aW9uX2Rlc2NyaXB0aW9uKQ0KbG9rIDwtIGNvdW50KGd1bl92aW9sZW5jZSwgImxvY2F0aW9uX2Rlc2NyaXB0aW9uIikgDQpnZ3Bsb3RseSggbG9rICU+JSBmaWx0ZXIobG9jYXRpb25fZGVzY3JpcHRpb24hPSIiKSAlPiUgDQogICAgICAgIGFycmFuZ2UoZGVzYyhmcmVxKSkgJT4lIHRvcF9uKDE1LCB3dD1mcmVxKSAlPiUNCiAgICAgICAgZ2dwbG90KGFlcyh4PWFzLmZhY3RvcihyZW9yZGVyKGxvY2F0aW9uX2Rlc2NyaXB0aW9uLGZyZXEpKSwgeT1mcmVxLCBmaWxsPWZyZXEsIHRleHQ9bG9jYXRpb25fZGVzY3JpcHRpb24pKSsgDQogICAgICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgK2xhYnMoeD0iIiwgeT0nJywgdGl0bGU9J051bWJlciBvZiBpbmNpZGVudHMgaW4gc3BlY2lmaWMgbG9jYXRpb25zJykgKw0KICAgICAgICBjb29yZF9mbGlwKCkgKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0ieWVsbG93IiwgaGlnaD0icmVkIikgKw0KICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSx0b29sdGlwPWMoInRleHQiLCAieSIpKQ0KYGBgDQoNCiMjIyBUaGUgYWJvdmUgY2hhcnQgc2hvd3MgdGhlIHBsYWNlcyB3aGVyZSBpbmNpZGVudHMgbW9zdCBvZnRlbiBvY2N1cnJlZC4gSXQgdHVybnMgb3V0IHRoYXQgdGhlIG1vc3QgY29tbW9uIGluY2lkZW50cyBvY2N1ciBpbiBrbm93biwgbGlrZWQgYW5kIGZyZXF1ZW50ZWQgcGxhY2VzIHN1Y2ggYXMgc2hvcHMsIGZhc3QtZm9vZCwgYW5kIGdhcyBzdGF0aW9ucy4=